Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow resizing the source image for a volume #1123

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions libvirt/resource_libvirt_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,7 @@ func resourceLibvirtVolumeCreate(ctx context.Context, d *schema.ResourceData, me
}

var img image
// an source image was given, this mean we can't choose size
if source, ok := d.GetOk("source"); ok {
// source and size conflict
if _, ok := d.GetOk("size"); ok {
return diag.Errorf("'size' can't be specified when also 'source' is given (the size will be set to the size of the source image")
}
if _, ok := d.GetOk("base_volume_id"); ok {
return diag.Errorf("'base_volume_id' can't be specified when also 'source' is given")
}
Expand Down Expand Up @@ -158,6 +153,12 @@ func resourceLibvirtVolumeCreate(ctx context.Context, d *schema.ResourceData, me
return diag.FromErr(err)
}

if desiredSize, ok := d.GetOk("size"); ok {
if uint64(desiredSize.(int)) < size {
return diag.Errorf("'size' can't be smaller than the size of the 'source'")
}
}

log.Printf("Image %s image is: %d bytes", img, size)
volumeDef.Capacity.Unit = "B"
volumeDef.Capacity.Value = size
Expand Down Expand Up @@ -270,6 +271,18 @@ be smaller than the backing store specified with
return diag.FromErr(err)
}

if _, ok := d.GetOk("source"); ok {
if desiredSize, ok := d.GetOk("size"); ok {
err = virConn.StorageVolResize(volume, uint64(desiredSize.(int)), 0)
if err != nil {
// don't save volume ID in case of error. This will taint the volume after.
// If we don't throw away the id, we will keep instead a broken volume.
d.Set("id", "")
return diag.Errorf("error while resizing image %s: %s", volume.Name, err)
}
}
}

return resourceLibvirtVolumeRead(ctx, d, meta)
}

Expand Down
120 changes: 120 additions & 0 deletions libvirt/resource_libvirt_volume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"testing"

libvirt "github.com/digitalocean/go-libvirt"
Expand Down Expand Up @@ -408,6 +409,125 @@ func TestAccLibvirtVolume_DownloadFromSourceFormat(t *testing.T) {
})
}

func TestAccLibvirtVolume_DownloadFromSourceSize(t *testing.T) {
size := 128 * 1024 * 1024
var volumeRaw libvirt.StorageVol
var volumeQCOW2 libvirt.StorageVol
randomVolumeNameRaw := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeNameQCOW := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeResourceRaw := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeResourceQCOW := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
qcow2Path, err := filepath.Abs("testdata/test.qcow2")
if err != nil {
t.Fatal(err)
}

rawPath, err := filepath.Abs("testdata/initrd.img")
if err != nil {
t.Fatal(err)
}

config := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
source = "%s"
size = %d
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_volume" "%s" {
name = "%s"
source = "%s"
size = %d
pool = "${libvirt_pool.%s.name}"
}`, randomPoolName, randomPoolName, randomPoolPath,
randomVolumeResourceRaw, randomVolumeNameRaw, fmt.Sprintf("file://%s", rawPath), size, randomPoolName,
randomVolumeResourceQCOW, randomVolumeNameQCOW, fmt.Sprintf("file://%s", qcow2Path), size, randomPoolName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtVolumeDestroy,
Steps: []resource.TestStep{
{
Config: config,
Check: resource.ComposeTestCheckFunc(
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeResourceRaw, &volumeRaw),
testAccCheckLibvirtVolumeExists("libvirt_volume."+randomVolumeResourceQCOW, &volumeQCOW2),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceRaw, "name", randomVolumeNameRaw),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceRaw, "format", "raw"),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceRaw, "size", fmt.Sprintf("%d", size)),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceQCOW, "name", randomVolumeNameQCOW),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceQCOW, "format", "qcow2"),
resource.TestCheckResourceAttr(
"libvirt_volume."+randomVolumeResourceQCOW, "size", fmt.Sprintf("%d", size)),
),
},
},
})
}

func TestAccLibvirtVolume_DownloadFromSourceSize_TooSmall(t *testing.T) {
size := 16
randomVolumeNameRaw := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeNameQCOW := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeResourceRaw := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomVolumeResourceQCOW := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolName := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
randomPoolPath := "/tmp/terraform-provider-libvirt-pool-" + randomPoolName
qcow2Path, err := filepath.Abs("testdata/test.qcow2")
if err != nil {
t.Fatal(err)
}

rawPath, err := filepath.Abs("testdata/initrd.img")
if err != nil {
t.Fatal(err)
}

config := fmt.Sprintf(`
resource "libvirt_pool" "%s" {
name = "%s"
type = "dir"
path = "%s"
}
resource "libvirt_volume" "%s" {
name = "%s"
source = "%s"
size = %d
pool = "${libvirt_pool.%s.name}"
}
resource "libvirt_volume" "%s" {
name = "%s"
source = "%s"
size = %d
pool = "${libvirt_pool.%s.name}"
}`, randomPoolName, randomPoolName, randomPoolPath,
randomVolumeResourceRaw, randomVolumeNameRaw, fmt.Sprintf("file://%s", rawPath), size, randomPoolName,
randomVolumeResourceQCOW, randomVolumeNameQCOW, fmt.Sprintf("file://%s", qcow2Path), size, randomPoolName)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckLibvirtVolumeDestroy,
Steps: []resource.TestStep{
{
Config: config,
ExpectError: regexp.MustCompile(`'size' can't be smaller than the size of the 'source'`),
},
},
})
}

func TestAccLibvirtVolume_Format(t *testing.T) {
var volume libvirt.StorageVol
randomVolumeResource := acctest.RandStringFromCharSet(10, acctest.CharSetAlpha)
Expand Down
7 changes: 3 additions & 4 deletions website/docs/r/volume.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ The following arguments are supported:
have to be specified using HTTP(S) urls for now.
* `size` - (Optional) The size of the volume in bytes (if you don't like this,
help fix [this issue](https://github.com/hashicorp/terraform/issues/3287).
If `source` is specified, `size` will be set to the source image file size.
`size` can be omitted if `source` is specified. `size` will then be set to the source image file size.
`size` can be omitted if `base_volume_id` or `base_volume_name` is specified. `size` will then be set to the base volume size.
If `size` is specified to be bigger than `base_volume_id` or `base_volume_name` size, you can use [cloudinit](https://cloudinit.readthedocs.io) if your OS supports it, with `libvirt_cloudinit_disk` and the [growpart](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#growpart) module to resize the partition.
If `source` is specified and `size` is omitted, it will be set to the source image file size.
`size` can also be omitted if `base_volume_id` or `base_volume_name` is specified. `size` will then be set to the base volume size.
If `size` is specified to be bigger than `base_volume_id`, `base_volume_name` or `source` size, you can use [cloudinit](https://cloudinit.readthedocs.io) if your OS supports it, with `libvirt_cloudinit_disk` and the [growpart](https://cloudinit.readthedocs.io/en/latest/topics/modules.html#growpart) module to resize the partition.
* `base_volume_id` - (Optional) The backing volume (CoW) to use for this volume.
* `base_volume_name` - (Optional) The name of the backing volume (CoW) to use
for this volume. Note well: when `base_volume_pool` is not specified the
Expand Down
Loading