Skip to content

Commit b0d4304

Browse files
committed
ci: add tiny linux image prep for acc shutdown test
1 parent 341c24b commit b0d4304

File tree

3 files changed

+111
-28
lines changed

3 files changed

+111
-28
lines changed

.github/workflows/test.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ jobs:
8484
sudo apt-get update
8585
sudo apt-get install -y \
8686
qemu-system-x86 \
87+
qemu-utils \
8788
libvirt-daemon-system \
8889
libvirt-clients \
8990
libvirt-dev
@@ -92,10 +93,28 @@ jobs:
9293
run: |
9394
sudo systemctl start libvirtd
9495
sudo systemctl status libvirtd
96+
# Normalize qemu runtime user on ephemeral runners to avoid storage DAC
97+
# mismatches (qemu uid cannot read newly created volume files).
98+
sudo sed -i 's/^#\?user = .*/user = "root"/' /etc/libvirt/qemu.conf
99+
sudo sed -i 's/^#\?group = .*/group = "root"/' /etc/libvirt/qemu.conf
100+
sudo sed -i 's/^#\?dynamic_ownership = .*/dynamic_ownership = 0/' /etc/libvirt/qemu.conf
101+
# Disable AppArmor confinement for QEMU so that VMs can access
102+
# volumes in non-default pool paths during acceptance tests.
103+
echo 'security_driver = "none"' | sudo tee -a /etc/libvirt/qemu.conf
104+
sudo systemctl restart libvirtd
95105
# Add runner to libvirt group
96106
sudo usermod -a -G libvirt runner
97107
# Change socket permissions to allow group access
98108
sudo chmod 666 /var/run/libvirt/libvirt-sock
109+
# Ensure default storage path is traversable by dynamically labeled qemu UIDs.
110+
sudo mkdir -p /var/lib/libvirt/images
111+
sudo chmod 1777 /var/lib/libvirt/images
112+
# Ensure default pool exists and is active in this ephemeral runner.
113+
if ! virsh -c qemu:///system pool-info default >/dev/null 2>&1; then
114+
virsh -c qemu:///system pool-define-as --name default --type dir --target /var/lib/libvirt/images
115+
fi
116+
virsh -c qemu:///system pool-start default || true
117+
virsh -c qemu:///system pool-autostart default || true
99118
100119
- name: Install Terraform
101120
if: matrix.tf-binary == 'terraform'
@@ -109,6 +128,16 @@ jobs:
109128
with:
110129
tofu_version: latest
111130

131+
- name: Cache acceptance test images
132+
uses: actions/cache@v4
133+
with:
134+
path: .cache/test-images
135+
key: ${{ runner.os }}-acc-images-alpine-3.23.3-r0
136+
137+
- name: Prepare Tiny Linux test image
138+
run: |
139+
make testdeps-acc-tinylinux
140+
112141
- name: Run Acceptance Tests
113142
env:
114143
TF_ACC: "1"
@@ -122,5 +151,38 @@ jobs:
122151
else
123152
export TF_ACC_TERRAFORM_PATH=$(which terraform)
124153
fi
154+
ACPI_IMAGE="$PWD/.cache/test-images/alpine-3.23.3-x86_64-bios-tiny-r0.qcow2"
155+
if [ -f "$ACPI_IMAGE" ]; then
156+
export LIBVIRT_TEST_ACPI_IMAGE="$ACPI_IMAGE"
157+
fi
125158
echo "Using Terraform CLI at: $TF_ACC_TERRAFORM_PATH"
159+
if [ -n "${LIBVIRT_TEST_ACPI_IMAGE:-}" ]; then
160+
echo "Using ACPI test image: $LIBVIRT_TEST_ACPI_IMAGE"
161+
else
162+
echo "LIBVIRT_TEST_ACPI_IMAGE not set; image-gated ACPI shutdown test will be skipped."
163+
fi
126164
make testacc
165+
166+
- name: Debug Libvirt/QEMU Storage Access
167+
if: always()
168+
run: |
169+
echo "=== qemu.conf ==="
170+
sudo grep -E '^(user|group|dynamic_ownership)[[:space:]]*=' /etc/libvirt/qemu.conf || true
171+
echo
172+
echo "=== libvirt daemon status ==="
173+
sudo systemctl status libvirtd --no-pager || true
174+
echo
175+
echo "=== qemu processes ==="
176+
ps -ef | grep -E '[q]emu-system|[l]ibvirtd|[v]irtqemud' || true
177+
echo
178+
echo "=== default pool info ==="
179+
virsh -c qemu:///system pool-info default || true
180+
virsh -c qemu:///system pool-dumpxml default || true
181+
echo
182+
echo "=== images dir permissions ==="
183+
ls -ld /var/lib/libvirt/images || true
184+
stat -c '%a %U:%G %n' /var/lib/libvirt/images || true
185+
echo
186+
echo "=== test volume file permissions ==="
187+
ls -l /var/lib/libvirt/images/test-volume-shutdown-image.qcow2 || true
188+
stat -c '%a %U:%G %n' /var/lib/libvirt/images/test-volume-shutdown-image.qcow2 || true

Makefile

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: help build install test testacc testacc-tofu sweep lint fmt clean generate testdeps-acc
1+
.PHONY: help build install test testacc testacc-tofu sweep lint fmt clean generate testdeps-acc testdeps-acc-tinylinux
22

33
# Default target
44
.DEFAULT_GOAL := help
@@ -9,6 +9,11 @@ CIRROS_VERSION ?= 0.6.2
99
TEST_IMAGE_DIR ?= .cache/test-images
1010
CIRROS_IMAGE ?= $(TEST_IMAGE_DIR)/cirros-$(CIRROS_VERSION)-x86_64-disk.img
1111
CIRROS_URL ?= https://download.cirros-cloud.net/$(CIRROS_VERSION)/cirros-$(CIRROS_VERSION)-x86_64-disk.img
12+
ALPINE_TINY_VERSION ?= 3.23.3
13+
ALPINE_TINY_RELEASE ?= r0
14+
ALPINE_TINY_VHD ?= $(TEST_IMAGE_DIR)/aws_alpine-$(ALPINE_TINY_VERSION)-x86_64-bios-tiny-$(ALPINE_TINY_RELEASE).vhd
15+
ALPINE_TINY_QCOW2 ?= $(TEST_IMAGE_DIR)/alpine-$(ALPINE_TINY_VERSION)-x86_64-bios-tiny-$(ALPINE_TINY_RELEASE).qcow2
16+
ALPINE_TINY_URL ?= https://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/cloud/aws_alpine-$(ALPINE_TINY_VERSION)-x86_64-bios-tiny-$(ALPINE_TINY_RELEASE).vhd
1217

1318
# Build flags
1419
LDFLAGS := -ldflags "-X main.version=$(VERSION)"
@@ -50,6 +55,27 @@ testdeps-acc: ## Download/cache acceptance test image dependencies (CirrOS)
5055
fi
5156
@echo "Set LIBVIRT_TEST_ACPI_IMAGE=$(CIRROS_IMAGE) to run image-based shutdown ACC test."
5257

58+
testdeps-acc-tinylinux: ## Download/cache Tiny Linux acceptance test image (Alpine BIOS tiny)
59+
@echo "Preparing Tiny Linux acceptance test image..."
60+
@mkdir -p $(TEST_IMAGE_DIR)
61+
@if [ ! -f "$(ALPINE_TINY_VHD)" ]; then \
62+
echo "Downloading $(ALPINE_TINY_URL) -> $(ALPINE_TINY_VHD)"; \
63+
curl -fL --retry 3 --retry-delay 2 -o "$(ALPINE_TINY_VHD)" "$(ALPINE_TINY_URL)"; \
64+
else \
65+
echo "Using cached VHD image: $(ALPINE_TINY_VHD)"; \
66+
fi
67+
@if [ ! -f "$(ALPINE_TINY_QCOW2)" ]; then \
68+
if ! command -v qemu-img >/dev/null 2>&1; then \
69+
echo "qemu-img is required to convert Tiny Linux VHD to QCOW2"; \
70+
exit 1; \
71+
fi; \
72+
echo "Converting $(ALPINE_TINY_VHD) -> $(ALPINE_TINY_QCOW2)"; \
73+
qemu-img convert -f vpc -O qcow2 "$(ALPINE_TINY_VHD)" "$(ALPINE_TINY_QCOW2)"; \
74+
else \
75+
echo "Using cached QCOW2 image: $(ALPINE_TINY_QCOW2)"; \
76+
fi
77+
@echo "Set LIBVIRT_TEST_ACPI_IMAGE=$(ALPINE_TINY_QCOW2) to run image-based shutdown ACC test."
78+
5379
testacc-tofu: ## Run acceptance tests with OpenTofu
5480
@TF_ACC_TERRAFORM_PATH=$$(which tofu) TF_ACC_PROVIDER_NAMESPACE=dmacvicar TF_ACC_PROVIDER_HOST=registry.terraform.io $(MAKE) testacc
5581

internal/provider/domain_resource_test.go

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -466,15 +466,14 @@ func TestAccDomainResource_destroyShutdownRunningWithImage(t *testing.T) {
466466
if _, err := os.Stat(imagePath); err != nil {
467467
t.Skipf("LIBVIRT_TEST_ACPI_IMAGE does not exist: %v", err)
468468
}
469-
testAccRequireDefaultPool(t)
470469

471470
resource.Test(t, resource.TestCase{
472471
PreCheck: func() { testAccPreCheck(t) },
473472
ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
474473
CheckDestroy: testAccCheckDomainDestroy,
475474
Steps: []resource.TestStep{
476475
{
477-
Config: testAccDomainResourceConfigDestroyShutdownRunningWithImage("test-domain-shutdown-image", "test-volume-shutdown-image", imagePath, 120),
476+
Config: testAccDomainResourceConfigDestroyShutdownRunningWithImage("test-domain-shutdown-image", "test-volume-shutdown-image", "test-pool-shutdown-image", "/var/lib/libvirt/images/test-pool-shutdown-image", imagePath, 120),
478477
Check: resource.ComposeAggregateTestCheckFunc(
479478
resource.TestCheckResourceAttr("libvirt_domain.test", "name", "test-domain-shutdown-image"),
480479
resource.TestCheckResourceAttr("libvirt_domain.test", "running", "true"),
@@ -484,31 +483,13 @@ func TestAccDomainResource_destroyShutdownRunningWithImage(t *testing.T) {
484483
{
485484
// Give the guest time to finish early boot before testing shutdown behavior.
486485
PreConfig: func() { time.Sleep(45 * time.Second) },
487-
Config: testAccDomainResourceConfigDestroyShutdownRunningWithImage("test-domain-shutdown-image", "test-volume-shutdown-image", imagePath, 120),
486+
Config: testAccDomainResourceConfigDestroyShutdownRunningWithImage("test-domain-shutdown-image", "test-volume-shutdown-image", "test-pool-shutdown-image", "/var/lib/libvirt/images/test-pool-shutdown-image", imagePath, 120),
488487
Destroy: true,
489488
},
490489
},
491490
})
492491
}
493492

494-
func testAccRequireDefaultPool(t *testing.T) {
495-
t.Helper()
496-
497-
ctx := context.Background()
498-
client, err := libvirtclient.NewClient(ctx, testAccLibvirtURI())
499-
if err != nil {
500-
t.Skipf("failed to create libvirt client: %v", err)
501-
}
502-
defer func() { _ = client.Close() }()
503-
504-
pool, err := client.Libvirt().StoragePoolLookupByName("default")
505-
if err != nil {
506-
t.Skipf("default storage pool not available: %v", err)
507-
}
508-
509-
// Ignore error if pool is already active; we only need a usable pool.
510-
_ = client.Libvirt().StoragePoolCreate(pool, 0)
511-
}
512493

513494
func TestAccDomainResource_updateWithRunning(t *testing.T) {
514495
resource.Test(t, resource.TestCase{
@@ -752,19 +733,33 @@ resource "libvirt_domain" "test" {
752733
`, name)
753734
}
754735

755-
func testAccDomainResourceConfigDestroyShutdownRunningWithImage(domainName, volumeName, imagePath string, timeout int64) string {
736+
func testAccDomainResourceConfigDestroyShutdownRunningWithImage(domainName, volumeName, poolName, poolPath, imagePath string, timeout int64) string {
756737
return fmt.Sprintf(`
738+
resource "libvirt_pool" "test" {
739+
name = %[3]q
740+
type = "dir"
741+
target = {
742+
path = %[4]q
743+
permissions = {
744+
mode = "777"
745+
}
746+
}
747+
}
748+
757749
resource "libvirt_volume" "test" {
758750
name = "%[2]s.qcow2"
759-
pool = "default"
751+
pool = libvirt_pool.test.name
760752
target = {
753+
permissions = {
754+
mode = "666"
755+
}
761756
format = {
762757
type = "qcow2"
763758
}
764759
}
765760
create = {
766761
content = {
767-
url = %[3]q
762+
url = %[5]q
768763
}
769764
}
770765
}
@@ -779,7 +774,7 @@ resource "libvirt_domain" "test" {
779774
780775
destroy = {
781776
shutdown = {
782-
timeout = %[4]d
777+
timeout = %[6]d
783778
}
784779
}
785780
@@ -798,7 +793,7 @@ resource "libvirt_domain" "test" {
798793
{
799794
source = {
800795
volume = {
801-
pool = "default"
796+
pool = libvirt_pool.test.name
802797
volume = libvirt_volume.test.name
803798
}
804799
}
@@ -822,7 +817,7 @@ resource "libvirt_domain" "test" {
822817
]
823818
}
824819
}
825-
`, domainName, volumeName, imagePath, timeout)
820+
`, domainName, volumeName, poolName, poolPath, imagePath, timeout)
826821
}
827822

828823
func testAccCheckDomainIsRunning(name string) resource.TestCheckFunc {

0 commit comments

Comments
 (0)