terraform-provider-libvirt/libvirt/resource_libvirt_domain_tes...

1860 lines
56 KiB
Go

package libvirt
import (
"fmt"
"log"
"net/url"
"os"
"path/filepath"
"testing"
testhelper "github.com/dmacvicar/terraform-provider-libvirt/libvirt/helper/test"
libvirt "github.com/digitalocean/go-libvirt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"libvirt.org/go/libvirtxml"
)
func TestAccLibvirtDomain_Basic(t *testing.T) {
var domain libvirt.Domain
randomResourceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
}`, randomResourceName, randomDomainName),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomResourceName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "name", randomDomainName),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "memory", "512"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "vcpu", "1"),
),
},
},
})
}
func TestAccLibvirtDomain_Description(t *testing.T) {
var domain libvirt.Domain
randomResourceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
description = "unit test description"
}`, randomResourceName, randomDomainName),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomResourceName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "name", randomDomainName),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "description", "unit test description"),
),
},
},
})
}
func TestAccLibvirtDomain_Detailed(t *testing.T) {
var domain libvirt.Domain
randomResourceName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
memory = 384
vcpu = 2
}`, randomResourceName, randomDomainName),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomResourceName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "name", randomDomainName),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "memory", "384"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomResourceName, "vcpu", "2"),
),
},
},
})
}
func TestAccLibvirtDomain_Volume(t *testing.T) {
var domain libvirt.Domain
var volume libvirt.StorageVol
randomVolumeName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
configVolAttached := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
disk {
volume_id = "${libvirt_volume.%s.id}"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomDomainName, randomDomainName, randomVolumeName)
configVolDettached := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configVolAttached,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeName, &volume),
),
},
{
Config: configVolDettached,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeDoesNotExists(&volume),
),
},
},
})
}
func TestAccLibvirtDomain_VolumeTwoDisks(t *testing.T) {
var domain libvirt.Domain
var volume libvirt.StorageVol
var volume2 libvirt.StorageVol
randomVolumeName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeName2 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
configVolAttached := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
disk {
volume_id = "${libvirt_volume.%s.id}"
}
disk {
volume_id = "${libvirt_volume.%s.id}"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomVolumeName2, randomVolumeName2, randomPoolName, randomDomainName, randomDomainName, randomVolumeName, randomVolumeName2)
configVolDettached := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configVolAttached,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeName, &volume),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeName2, &volume2),
),
},
{
Config: configVolDettached,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeDoesNotExists(&volume),
testAccCheckLibvirtVolumeDoesNotExists(&volume2),
),
},
},
})
}
// tests that disk driver is set correctly for the volume format.
func TestAccLibvirtDomain_VolumeDriver(t *testing.T) {
var domain libvirt.Domain
var volumeRaw libvirt.StorageVol
var volumeQCOW2 libvirt.StorageVol
randomVolumeQCOW2 := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeRaw := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
format = "raw"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_volume" "%s" {
name = "%s"
format = "qcow2"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
disk {
volume_id = "${libvirt_volume.%s.id}"
}
disk {
volume_id = "${libvirt_volume.%s.id}"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeRaw, randomVolumeRaw, randomPoolName, randomVolumeQCOW2, randomVolumeQCOW2, randomPoolName, randomDomainName, randomDomainName, randomVolumeRaw, randomVolumeQCOW2)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeRaw, &volumeRaw),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeQCOW2, &volumeQCOW2),
// Check that each disk has the appropriate driver
testAccCheckLibvirtDomainDescription(&domain, func(domainDef libvirtxml.Domain) error {
if domainDef.Devices.Disks[0].Driver.Type != "raw" {
return fmt.Errorf("Expected disk to have RAW driver")
}
if domainDef.Devices.Disks[1].Driver.Type != "qcow2" {
return fmt.Errorf("Expected disk to have QCOW2 driver")
}
return nil
})),
},
},
})
}
func TestAccLibvirtDomain_ScsiDisk(t *testing.T) {
var domain libvirt.Domain
randomVolumeName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
configScsi := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
disk {
volume_id = "${libvirt_volume.%s.id}"
scsi = "true"
wwn = "000000123456789a"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomDomainName, randomDomainName, randomVolumeName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configScsi,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtScsiDisk("000000123456789a", &domain),
),
},
},
})
}
func TestAccLibvirtDomain_BlockDevice(t *testing.T) {
skipIfAccDisabled(t)
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomDeviceName := acctest.RandStringFromCharSet(33, acctest.CharSetAlpha)
blockDev, err := testhelper.CreateTempFormattedLoopDevice(t, randomDeviceName)
if err != nil {
t.Fatal(err)
}
defer func() {
if err := blockDev.Cleanup(); err != nil {
t.Errorf("Error cleaning up loop device %s: %s", blockDev, err)
}
}()
configBlockDevice := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
disk {
block_device = "%s"
}
}`, randomDomainName, randomDomainName, blockDev.LoopDevice)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configBlockDevice,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtBlockDevice(blockDev.LoopDevice, &domain),
),
},
},
})
}
func TestAccLibvirtDomain_URLDisk(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
fws := newFileWebServer(t)
fws.Start()
defer fws.Close()
isoPath, err := filepath.Abs("testdata/tcl.iso")
if err != nil {
t.Fatal(err)
}
u, err := fws.AddFile(isoPath)
if err != nil {
t.Error(err)
}
url, err := url.Parse(u)
if err != nil {
t.Error(err)
}
configURL := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
disk {
url = "%s"
}
}`, randomDomainName, randomDomainName, url.String())
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configURL,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtURLDisk(url, &domain),
),
},
},
})
}
func TestAccLibvirtDomain_MultiISODisks(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
isoPath, err := filepath.Abs("testdata/tcl.iso")
if err != nil {
t.Fatal(err)
}
configFourDisks := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
disk {
file = "%s"
}
disk {
file = "%s"
}
disk {
file = "%s"
}
disk {
file = "%s"
}
}`, randomDomainName, randomDomainName, isoPath, isoPath, isoPath, isoPath)
configWithCloudInit := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_cloudinit_disk" "%s" {
name = "%s"
user_data = "#cloud-config"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
cloudinit = "${libvirt_cloudinit_disk.%s.id}"
disk {
file = "%s"
}
disk {
file = "%s"
}
disk {
file = "%s"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomDomainName, randomDomainName, randomPoolName, randomDomainName, randomDomainName, randomDomainName, isoPath, isoPath, isoPath)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configFourDisks,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtMultiISODisks(&domain),
),
},
{
Config: configWithCloudInit,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtMultiISODisks(&domain),
),
},
},
})
}
func TestAccLibvirtDomain_KernelInitrdCmdline(t *testing.T) {
var domain libvirt.Domain
var kernel libvirt.StorageVol
var initrd libvirt.StorageVol
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "kernel" {
source = "testdata/tetris.elf"
name = "kernel"
pool = "${libvirt_pool.%s.name}"
format = "raw"
}
resource "libvirt_volume" "initrd" {
source = "testdata/initrd.img"
name = "initrd"
pool = "${libvirt_pool.%s.name}"
format = "raw"
}
resource "libvirt_domain" "%s" {
name = "terraform-test-domain"
kernel = "${libvirt_volume.kernel.id}"
initrd = "${libvirt_volume.initrd.id}"
cmdline = [
{
foo = "1"
bar = "bye"
},
{
foo = "2"
}
]
}`, randomPoolName, randomPoolName, randomPoolPath, randomPoolName, randomPoolName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtVolumeExists("libvirt_volume.kernel", &kernel),
testAccCheckLibvirtVolumeExists("libvirt_volume.initrd", &initrd),
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtDomainKernelInitrdCmdline(&domain, &kernel, &initrd),
),
},
},
})
}
func TestAccLibvirtDomain_NetworkInterface(t *testing.T) {
skipIfPrivilegedDisabled(t)
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomNetworkName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
currentDir, err := os.Getwd()
if err != nil {
t.Fatal("Unexpected error:", err)
}
config := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
addresses = ["10.17.3.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_name = "${libvirt_network.%s.name}"
hostname = "myhost"
mac = "52:54:00:A9:F5:17"
wait_for_lease = true
}
network_interface {
network_id = "${libvirt_network.%s.id}"
hostname = "myhost"
mac = "52:54:00:A9:F5:19"
wait_for_lease = true
}
disk {
file = "%s/testdata/tcl.iso"
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName, randomNetworkName, randomNetworkName, currentDir)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
ExpectNonEmptyPlan: false,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.0.network_name", randomNetworkName),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.0.mac", "52:54:00:A9:F5:17"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.0.hostname", "myhost"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.1.network_name", randomNetworkName),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.1.mac", "52:54:00:A9:F5:19"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.1.hostname", "myhost"),
),
},
},
})
}
func TestAccLibvirtDomain_CheckDHCPEntries(t *testing.T) {
skipIfPrivilegedDisabled(t)
var domain libvirt.Domain
var network libvirt.Network
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomNetworkName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
configWithDomain := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
mode = "nat"
domain = "%s"
addresses = ["192.0.0.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_id = "${libvirt_network.%s.id}"
hostname = "terraform-test"
addresses = ["192.0.0.2"]
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName, randomDomainName, randomNetworkName)
configWithoutDomain := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
mode = "nat"
domain = "%s"
addresses = ["192.0.0.0/24"]
}`, randomNetworkName, randomNetworkName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configWithDomain,
ExpectNonEmptyPlan: true,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtNetworkExists("libvirt_network."+randomNetworkName, &network),
),
},
{
Config: configWithoutDomain,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDestroyLeavesIPs(
"libvirt_network."+randomNetworkName,
"192.0.0.2",
),
),
},
{
Config: configWithDomain,
ExpectNonEmptyPlan: true,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
),
},
},
})
}
func TestAccLibvirtDomain_Graphics(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
config := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
graphics {
type = "spice"
autoport = "true"
listen_type = "none"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomDomainName, randomDomainName)
configListenAddress := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
graphics {
type = "spice"
autoport = "true"
listen_type = "address"
listen_address = "127.0.1.1"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.type", "spice"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.autoport", "true"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.listen_type", "none"),
),
},
},
})
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: configListenAddress,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.type", "spice"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.autoport", "true"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.listen_type", "address"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "graphics.0.listen_address", "127.0.1.1"),
),
},
},
})
}
func TestAccLibvirtDomain_IgnitionObject(t *testing.T) {
var domain libvirt.Domain
var volume libvirt.StorageVol
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
randomIgnitionName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
data "ignition_systemd_unit" "acceptance-test-systemd" {
name = "example.service"
content = "[Service]\nType=oneshot\nExecStart=/usr/bin/echo Hello World\n\n[Install]\nWantedBy=multi-user.target"
}
data "ignition_config" "acceptance-test-config" {
systemd = [
"${data.ignition_systemd_unit.acceptance-test-systemd.rendered}",
]
}
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_ignition" "%s" {
name = "ignition"
content = "${data.ignition_config.acceptance-test-config.rendered}"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "terraform-test-domain"
coreos_ignition = "${libvirt_ignition.%s.id}"
}
`, randomPoolName, randomPoolName, randomPoolPath, randomIgnitionName, randomPoolName, randomDomainName, randomIgnitionName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckIgnitionVolumeExists("libvirt_ignition."+randomIgnitionName, &volume),
testAccCheckIgnitionXML(&domain, &volume, "opt/com.coreos/config"),
),
},
},
})
}
func TestAccLibvirtDomain_Cpu(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
cpu {
mode = "custom"
}
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "cpu.0.mode", "custom"),
),
},
},
})
}
func TestAccLibvirtDomain_Video(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
video {
type = "vga"
}
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "video.0.type", "vga"),
),
},
},
})
}
func TestAccLibvirtDomain_Autostart(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
autostartTrue := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
autostart = true
}`, randomDomainName, randomDomainName)
autostartFalse := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
autostart = false
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: autostartTrue,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr("libvirt_domain."+randomDomainName, "autostart", "true"),
),
},
{
Config: autostartFalse,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr("libvirt_domain."+randomDomainName, "autostart", "false"),
),
},
},
})
}
func TestAccLibvirtDomain_Filesystems(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
filesystem {
source = "/tmp"
target = "tmp"
readonly = false
}
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "filesystem.0.source", "/tmp"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "filesystem.0.target", "tmp"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "filesystem.0.readonly", "false"),
),
},
},
})
}
func testAccCheckLibvirtDomainExists(name string, domain *libvirt.Domain) resource.TestCheckFunc {
return func(state *terraform.State) error {
rs, err := getResourceFromTerraformState(name, state)
if err != nil {
return err
}
virConn := testAccProvider.Meta().(*Client).libvirt
retrievedDomain, err := virConn.DomainLookupByUUID(parseUUID(rs.Primary.ID))
if err != nil {
return err
}
log.Printf("[DEBUG] The ID is %s", rs.Primary.ID)
if uuidString(retrievedDomain.UUID) == "" {
return fmt.Errorf("UUID is blank")
}
if uuidString(retrievedDomain.UUID) != rs.Primary.ID {
return fmt.Errorf("Libvirt domain not found")
}
*domain = retrievedDomain
return nil
}
}
func testAccCheckIgnitionXML(domain *libvirt.Domain, volume *libvirt.StorageVol, fwCfg string) resource.TestCheckFunc {
return func(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
domainDef, err := getXMLDomainDefFromLibvirt(virConn, *domain)
if err != nil {
return fmt.Errorf("Error retrieving libvirt domain XML description from existing domain: %w", err)
}
if volume.Key == "" {
return fmt.Errorf("Ignition key is blank")
}
ignStr := fmt.Sprintf("name=%s,file=%s", fwCfg, volume.Key)
cmdLine := domainDef.QEMUCommandline.Args
for i, cmd := range cmdLine {
if i == 1 && cmd.Value != ignStr {
return fmt.Errorf("libvirt domain fw_cfg XML is incorrect %s", cmd.Value)
}
}
return nil
}
}
func testAccCheckLibvirtScsiDisk(n string, domain *libvirt.Domain) resource.TestCheckFunc {
return testAccCheckLibvirtDomainDescription(domain, func(domainDef libvirtxml.Domain) error {
disks := domainDef.Devices.Disks
for _, disk := range disks {
if diskBus := disk.Target.Bus; diskBus != "scsi" {
return fmt.Errorf("Disk bus is not scsi")
}
if wwn := disk.WWN; wwn != n {
return fmt.Errorf("Disk wwn %s is not equal to %s", wwn, n)
}
}
return nil
})
}
func testAccCheckLibvirtBlockDevice(n string, domain *libvirt.Domain) resource.TestCheckFunc {
return testAccCheckLibvirtDomainDescription(domain, func(domainDef libvirtxml.Domain) error {
disks := domainDef.Devices.Disks
for _, disk := range disks {
if disk.Source.Block == nil {
return fmt.Errorf("Disk is not a block device")
}
if dev := disk.Source.Block.Dev; dev != n {
return fmt.Errorf("Disk source %s does not equal %s", dev, n)
}
}
return nil
})
}
func testAccCheckLibvirtDomainDescription(domain *libvirt.Domain, checkFunc func(libvirtxml.Domain) error) resource.TestCheckFunc {
return func(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
domainDef, err := getXMLDomainDefFromLibvirt(virConn, *domain)
if err != nil {
return fmt.Errorf("Error retrieving libvirt domain XML description from existing domain: %w", err)
}
return checkFunc(domainDef)
}
}
func testAccCheckLibvirtURLDisk(u *url.URL, domain *libvirt.Domain) resource.TestCheckFunc {
return func(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
domainDef, err := getXMLDomainDefFromLibvirt(virConn, *domain)
if err != nil {
return fmt.Errorf("Error getting libvirt XML definition from existing libvirt domain: %w", err)
}
disks := domainDef.Devices.Disks
for _, disk := range disks {
if disk.Source.Network == nil {
return fmt.Errorf("Disk type is not network")
}
if disk.Source.Network.Protocol != u.Scheme {
return fmt.Errorf("Disk protocol is not %s", u.Scheme)
}
if disk.Source.Network.Name != u.Path {
return fmt.Errorf("Disk name is not %s", u.Path)
}
if len(disk.Source.Network.Hosts) < 1 {
return fmt.Errorf("Disk has no hosts defined")
}
if disk.Source.Network.Hosts[0].Name != u.Hostname() {
return fmt.Errorf("Disk hostname is not %s", u.Hostname())
}
}
return nil
}
}
func testAccCheckLibvirtMultiISODisks(domain *libvirt.Domain) resource.TestCheckFunc {
return func(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
domainDef, err := getXMLDomainDefFromLibvirt(virConn, *domain)
if err != nil {
return fmt.Errorf("Error getting libvirt XML definition from existing libvirt domain: %w", err)
}
disks := domainDef.Devices.Disks
for _, disk := range disks {
if disk.Device != "cdrom" {
return fmt.Errorf("Disk device type is not cdrom")
}
}
if len(disks) != 4 {
return fmt.Errorf("Expected amount of disks not found")
}
return nil
}
}
func testAccCheckLibvirtDestroyLeavesIPs(name string, ip string) resource.TestCheckFunc {
return func(state *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
networkDef, err := getNetworkDef(state, name, virConn)
if err != nil {
return err
}
for _, ips := range networkDef.IPs {
for _, dhcpHost := range ips.DHCP.Hosts {
if dhcpHost.IP == ip {
return nil
}
}
}
return fmt.Errorf("Hostname with ip '%s' does not have a dhcp entry in network", ip)
}
}
func testAccCheckLibvirtDomainKernelInitrdCmdline(domain *libvirt.Domain, kernel *libvirt.StorageVol, initrd *libvirt.StorageVol) resource.TestCheckFunc {
return func(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
domainDef, err := getXMLDomainDefFromLibvirt(virConn, *domain)
if err != nil {
return fmt.Errorf("Error retrieving libvirt domain XML description from existing domain: %w", err)
}
if kernel.Key == "" {
return fmt.Errorf("Can't get kernel volume id")
}
if domainDef.OS.Kernel != kernel.Key {
return fmt.Errorf("Kernel is not set correctly: '%s' vs '%s'", domainDef.OS.Kernel, kernel.Key)
}
if initrd.Key == "" {
return fmt.Errorf("Can't get initrd volume id")
}
if domainDef.OS.Initrd != initrd.Key {
return fmt.Errorf("Initrd is not set correctly: '%s' vs '%s'", domainDef.OS.Initrd, initrd.Key)
}
if domainDef.OS.Cmdline != "bar=bye foo=1 foo=2" {
return fmt.Errorf("Kernel args not set correctly: '%s'", domainDef.OS.Cmdline)
}
return nil
}
}
func createNvramFile(_ *testing.T) (string, error) {
// size of an accepted, valid, nvram backing store
nvramDummyBuffer := make([]byte, 131072)
file, err := os.CreateTemp("", "nvram")
if err != nil {
return "", err
}
err = file.Chmod(0o777)
if err != nil {
return "", err
}
_, err = file.Write(nvramDummyBuffer)
if err != nil {
return "", err
}
if file.Close() != nil {
return "", err
}
return file.Name(), nil
}
func TestAccLibvirtDomainFirmware(t *testing.T) {
nvramPath, err := createNvramFile(t)
if err != nil {
t.Fatal(err)
}
defer os.Remove(nvramPath)
firmware := "/usr/share/qemu/ovmf-x86_64-code.bin"
if _, err := os.Stat(firmware); os.IsNotExist(err) {
firmware = "/usr/share/ovmf/OVMF.fd"
if _, err := os.Stat(firmware); os.IsNotExist(err) {
t.Skipf("Can't test domain custom firmware: OVMF firmware not found: %s", err)
}
}
template := "/usr/share/qemu/ovmf-x86_64-vars.bin"
if _, err := os.Stat(template); os.IsNotExist(err) {
template = "/usr/share/qemu/OVMF.fd"
if _, err := os.Stat(template); os.IsNotExist(err) {
t.Skipf("Can't test domain custom firmware template: OVMF template not found: %s", err)
}
}
t.Run("No Template", func(t *testing.T) {
subtestAccLibvirtDomainFirmwareNoTemplate(t, nvramPath, firmware)
})
t.Run("With Template", func(t *testing.T) {
subtestAccLibvirtDomainFirmwareTemplate(t, nvramPath, firmware, template)
})
}
func subtestAccLibvirtDomainFirmwareNoTemplate(t *testing.T, nvramPath string, firmware string) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "terraform-test-firmware-no-template"
firmware = "%s"
nvram {
file = "%s"
}
}`, randomDomainName, firmware, nvramPath)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "name", "terraform-test-firmware-no-template"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "nvram.0.file", nvramPath),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "firmware", firmware),
),
},
},
})
}
func subtestAccLibvirtDomainFirmwareTemplate(t *testing.T, nvramPath string, firmware string, template string) {
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
var domain libvirt.Domain
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "terraform-test-firmware-with-template"
firmware = "%s"
nvram {
file = "%s"
template = "%s"
}
}`, randomDomainName, firmware, nvramPath, template)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "name", "terraform-test-firmware-with-template"),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "nvram.0.file", nvramPath),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "nvram.0.template", template),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "firmware", firmware),
),
},
},
})
}
func TestAccLibvirtDomain_MachineType(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
// Using machine type of pc as this is earliest QEMU target
// and so most likely to be available
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
machine = "pc"
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr("libvirt_domain."+randomDomainName, "machine", "pc"),
),
},
},
})
}
func TestAccLibvirtDomain_ArchType(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
// Using i686 as architecture in case anyone running tests on an i686 only host
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
arch = "i686"
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr("libvirt_domain."+randomDomainName, "arch", "i686"),
),
},
},
})
}
func testAccCheckLibvirtNetworkExists(name string, network *libvirt.Network) resource.TestCheckFunc {
return func(state *terraform.State) error {
rs, err := getResourceFromTerraformState(name, state)
if err != nil {
return err
}
virConn := testAccProvider.Meta().(*Client).libvirt
retrievedNetwork, err := virConn.NetworkLookupByUUID(parseUUID(rs.Primary.ID))
if err != nil {
return err
}
log.Printf("[DEBUG] The ID is %s", rs.Primary.ID)
if uuidString(retrievedNetwork.UUID) == "" {
return fmt.Errorf("UUID is blank")
}
if uuidString(retrievedNetwork.UUID) != rs.Primary.ID {
return fmt.Errorf("Libvirt network not found")
}
network = &retrievedNetwork
return nil
}
}
// we want to destroy (shutdown volume after creation).
func TestAccLibvirtDomain_ShutoffDomain(t *testing.T) {
var domain libvirt.Domain
var volume libvirt.StorageVol
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
running = false
disk {
volume_id = "${libvirt_volume.%s.id}"
}
}`, randomPoolName, randomPoolName, randomPoolPath, randomVolumeName, randomVolumeName, randomPoolName, randomDomainName, randomDomainName, randomVolumeName),
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeName, &volume),
testAccCheckLibvirtDomainStateEqual("libvirt_domain."+randomDomainName, &domain, "shutoff"),
),
},
},
})
}
func TestAccLibvirtDomain_ShutoffMultiDomainsRunning(t *testing.T) {
var domain libvirt.Domain
var domain2 libvirt.Domain
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: `
resource "libvirt_domain" "domainoff" {
name = "domainfalse"
vcpu = 1
running = false
}
resource "libvirt_domain" "domainok" {
name = "domaintrue"
vcpu = 1
running = true
}`,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainStateEqual("libvirt_domain.domainoff", &domain, "shutoff"),
testAccCheckLibvirtDomainStateEqual("libvirt_domain.domainok", &domain2, "running"),
),
},
},
})
}
func TestAccLibvirtDomain_CaseInsensitiveAttrs_MAC(t *testing.T) {
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
mac = "52:54:00:b2:2f:88"
}
}`, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
// libvirt always returns upper-cased
resource.TestCheckResourceAttr("libvirt_domain."+randomDomainName, "network_interface.0.mac", "52:54:00:B2:2F:88"),
),
// because the attribute is case insensitive, there should be no plan
ExpectNonEmptyPlan: false,
},
},
})
}
func testAccCheckLibvirtDomainStateEqual(name string, domain *libvirt.Domain, exptectedState string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, err := getResourceFromTerraformState(name, s)
if err != nil {
return err
}
virConn := testAccProvider.Meta().(*Client).libvirt
retrievedDomain, err := virConn.DomainLookupByUUID(parseUUID(rs.Primary.ID))
if err != nil {
return err
}
if uuidString(retrievedDomain.UUID) == "" {
return fmt.Errorf("UUID is blank")
}
if uuidString(retrievedDomain.UUID) != rs.Primary.ID {
return fmt.Errorf("Libvirt domain not found")
}
*domain = retrievedDomain
state, err := domainGetState(virConn, *domain)
if err != nil {
return fmt.Errorf("could not get domain state: %w", err)
}
if state != exptectedState {
return fmt.Errorf("Domain state should be == %s, but is %s", exptectedState, state)
}
return nil
}
}
func TestAccLibvirtDomain_Import(t *testing.T) {
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: fmt.Sprintf(`
resource "libvirt_domain" "%s" {
name = "%s"
memory = 384
vcpu = 2
}`, randomDomainName, randomDomainName),
},
{
ResourceName: "libvirt_domain." + randomDomainName,
ImportState: true,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain.%s-2", &domain),
resource.TestCheckResourceAttr(
"libvirt_domain.%s-2", "name", randomDomainName),
resource.TestCheckResourceAttr(
"libvirt_domain.%s-2", "memory", "384"),
resource.TestCheckResourceAttr(
"libvirt_domain.%s-2", "vcpu", "2"),
),
},
},
})
}
func TestAccLibvirtDomain_XSLT_UnsupportedAttribute(t *testing.T) {
skipIfPrivilegedDisabled(t)
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomNetworkName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
addresses = ["10.17.3.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_name = "default"
}
xml {
xslt = <<EOF
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/domain/devices/interface[@type='network']/model/@type">
<xsl:attribute name="type">
<xsl:value-of select="'e1000'"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
EOF
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtDomainDescription(&domain, func(domainDef libvirtxml.Domain) error {
if domainDef.Devices.Interfaces[0].Model.Type != "e1000" {
return fmt.Errorf("Expecting XSLT to transform network model to e1000")
}
return nil
}),
),
},
},
})
}
// If using XSLT to transform a supported attribute by the terraform
// provider schema, the provider will try to change it back to the
// known state.
// Therefore we explicitly advise against using it with existing
// schema attributes.
func TestAccLibvirtDomain_XSLT_SupportedAttribute(t *testing.T) {
skipIfPrivilegedDisabled(t)
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomNetworkName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
addresses = ["10.17.3.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_name = "default"
}
xml {
xslt = <<EOF
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/domain/devices/interface[@type='network']/source/@network">
<xsl:attribute name="network">
<xsl:value-of select="'%s'"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
EOF
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName, randomNetworkName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
ExpectNonEmptyPlan: true,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
resource.TestCheckResourceAttr(
"libvirt_domain."+randomDomainName, "network_interface.0.network_name", randomNetworkName),
),
},
},
})
}
// changed whitespace in the xslt should create an empty plan
// as the suppress diff function should take care of seeing they are equivalent.
func TestAccLibvirtDomain_XSLT_Whitespace(t *testing.T) {
skipIfPrivilegedDisabled(t)
var domain libvirt.Domain
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomNetworkName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
addresses = ["10.17.3.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_name = "default"
}
xml {
xslt = <<EOF
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/domain/devices/interface[@type='network']/model/@type">
<xsl:attribute name="type">
<xsl:value-of select="'e1000'"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
EOF
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName)
configAfter := fmt.Sprintf(`
resource "libvirt_network" "%s" {
name = "%s"
addresses = ["10.17.3.0/24"]
}
resource "libvirt_domain" "%s" {
name = "%s"
network_interface {
network_name = "default"
}
xml {
xslt = <<EOF
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>
<xsl:template match="/domain/devices/interface[@type='network']/model/@type">
<xsl:attribute name="type"><xsl:value-of select="'e1000'"/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
EOF
}
}`, randomNetworkName, randomNetworkName, randomDomainName, randomDomainName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtDomainDescription(&domain, func(domainDef libvirtxml.Domain) error {
if domainDef.Devices.Interfaces[0].Model.Type != "e1000" {
return fmt.Errorf("Expecting XSLT to transform network model to e1000")
}
return nil
}),
),
},
{
Config: configAfter,
ExpectNonEmptyPlan: false,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckLibvirtDomainDescription(&domain, func(domainDef libvirtxml.Domain) error {
if domainDef.Devices.Interfaces[0].Model.Type != "e1000" {
return fmt.Errorf("Expecting XSLT to transform network model to e1000")
}
return nil
}),
),
},
},
})
}
func testAccCheckLibvirtDomainDestroy(s *terraform.State) error {
virConn := testAccProvider.Meta().(*Client).libvirt
for _, rs := range s.RootModule().Resources {
if rs.Type != "libvirt_domain" {
continue
}
// Try to find the server
_, err := virConn.DomainLookupByUUID(parseUUID(rs.Primary.ID))
if err == nil {
return fmt.Errorf(
"Error waiting for domain (%s) to be destroyed: %w",
rs.Primary.ID, err)
}
}
return nil
}
func TestAccLibvirtDomain_FwCfgName(t *testing.T) {
/*
Ignition file is mounted of domain through `fw_cfg`.
`fw_cfg` stands for firmware config is defined by a key and a value.
The key is generally prefixed by `opt/`
The value can be a file
Finally the file will be mounted on /sys/firmware/qemu_fw_cfg/by_name/<key-name>
in example: CoreOS will fetch ignition file from /opt/com.coreos/config, but Flatcar Linux will fetch it from /opt/org.flatcar-linux/config
We need to test if we can override the key name.
*/
var domain libvirt.Domain
var volume libvirt.StorageVol
randomDomainName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomFwCfgName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
randomIgnitionName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
config := fmt.Sprintf(`
data "ignition_systemd_unit" "acceptance-test-systemd" {
name = "whatever.service"
content = "[Service]\nType=oneshot\nExecStart=/usr/bin/echo Hello World\n\n[Install]\nWantedBy=multi-user.target"
}
data "ignition_config" "acceptance-test-config-fw-cfg" {
systemd = [
"${data.ignition_systemd_unit.acceptance-test-systemd.rendered}",
]
}
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_ignition" "%s" {
name = "ignition"
content = "${data.ignition_config.acceptance-test-config-fw-cfg.rendered}"
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_domain" "%s" {
name = "%s"
coreos_ignition = "${libvirt_ignition.%s.id}"
fw_cfg_name = "%s"
}
`, randomPoolName, randomPoolName, randomPoolPath, randomIgnitionName, randomPoolName, randomDomainName, randomDomainName, randomIgnitionName, randomFwCfgName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtDomainDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtDomainExists("libvirt_domain."+randomDomainName, &domain),
testAccCheckIgnitionVolumeExists("libvirt_ignition."+randomIgnitionName, &volume),
testAccCheckIgnitionXML(&domain, &volume, randomFwCfgName),
),
},
},
})
}