From 8152da85dc3036dc8d827ddfea76b62fd6f1ab17 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Mon, 10 Sep 2018 12:19:17 +0200 Subject: [PATCH 1/7] Do not prevent specifying 'size' when using a base volume. --- libvirt/resource_libvirt_volume.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/libvirt/resource_libvirt_volume.go b/libvirt/resource_libvirt_volume.go index 6846c8a81..a336e26c2 100644 --- a/libvirt/resource_libvirt_volume.go +++ b/libvirt/resource_libvirt_volume.go @@ -161,10 +161,6 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error } if baseVolumeID, ok := d.GetOk("base_volume_id"); ok { - if _, ok := d.GetOk("size"); ok { - return fmt.Errorf("'size' can't be specified when also 'base_volume_id' is given (the size will be set to the size of the backing image") - } - if _, ok := d.GetOk("base_volume_name"); ok { return fmt.Errorf("'base_volume_name' can't be specified when also 'base_volume_id' is given") } @@ -182,9 +178,6 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error } if baseVolumeName, ok := d.GetOk("base_volume_name"); ok { - if _, ok := d.GetOk("size"); ok { - return fmt.Errorf("'size' can't be specified when also 'base_volume_name' is given (the size will be set to the size of the backing image") - } volume = nil baseVolumePool := pool @@ -204,6 +197,19 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error if err != nil { return fmt.Errorf("Could not retrieve backing store %s", baseVolumeName.(string)) } + + // does the backing store have some size information, check at least that it is not smaller than the backing store? + volumeDef.Capacity.Value = uint64(d.Get("size").(int)) + if _, ok := d.GetOk("size"); ok { + backingStoreVolumeDef, err := newDefVolumeFromLibvirt(baseVolume) + if err != nil { + return err + } + + if backingStoreVolumeDef.Capacity != nil && volumeDef.Capacity.Value < backingStoreVolumeDef.Capacity.Value { + return fmt.Errorf("When 'size' is specified, it shouldn't be smaller than the backing store specified with 'base_volume_id'") + } + } volumeDef.BackingStore = &backingStoreDef } From 9836fe6eee583b5dea68c5365210ff44e6e0f2e8 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Mon, 10 Sep 2018 23:13:45 +0200 Subject: [PATCH 2/7] Add example for resizing the base image with cloud-init --- examples/resize_base/.gitignore | 4 ++ examples/resize_base/README.md | 4 ++ examples/resize_base/id_rsa | 27 ++++++++++++ examples/resize_base/id_rsa.pub | 1 + examples/resize_base/main.tf | 73 +++++++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 examples/resize_base/.gitignore create mode 100644 examples/resize_base/README.md create mode 100644 examples/resize_base/id_rsa create mode 100644 examples/resize_base/id_rsa.pub create mode 100644 examples/resize_base/main.tf diff --git a/examples/resize_base/.gitignore b/examples/resize_base/.gitignore new file mode 100644 index 000000000..da4f3c41d --- /dev/null +++ b/examples/resize_base/.gitignore @@ -0,0 +1,4 @@ +*.img +*.qcow2 +*.tfstate* +.terraform \ No newline at end of file diff --git a/examples/resize_base/README.md b/examples/resize_base/README.md new file mode 100644 index 000000000..56b76ed32 --- /dev/null +++ b/examples/resize_base/README.md @@ -0,0 +1,4 @@ + +This example takes a base image of 2G and uses it as the backing store of a bigger volume. _cloud-init_ is then used to resize the original partition to the new available space. + +See https://github.com/dmacvicar/terraform-provider-libvirt/issues/369 diff --git a/examples/resize_base/id_rsa b/examples/resize_base/id_rsa new file mode 100644 index 000000000..f57776b98 --- /dev/null +++ b/examples/resize_base/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAzKsKBhrbzq5Ur80tDE2t5fsAkJ5qHnm5w0v9cEVKkkPgeUTi ++VswoBAFMjf1nTKbGZAEsXS8nphD4XURdztV+p1m7XopzS1uC0DDyPm5TxWptMSd +ZAS2DA0l0eeyvKmNGveKKcrgFAjwMENr3syjwfNKao5waYSkLBvvgp6oWkPJG7RK +SER6z/n1JBhJoGwAu8plNsLWRhhoYrGMaVTsOcYj2ohFNM3c59UarwLPsKlV2TRJ +PFpLkGm69BYMR2fxHyFLn1iEMvy21X0wcs4bh2SLB8qTu1uDko6MneAAlFQgPgvJ +cIYWhgdyIi0VGhatvPFH4E0C2wfADqV3us5qzwIDAQABAoIBAQCJ0LplNfzBBX6d +ConE+SGZ9RSCTUmjz8+YhDjaOq5mIzKqNgqoYhEyFteI40mOWp857VJbtAG2wU0k +KdJi+R+CLC88xcAUGv04spmjYRS4/htST/qzeMClCM1otJ4UkA8mE32Desq8cvBZ +b2zZj+7NEOgRLGzhgKGT2hPDXtZ6QGn9+K6xUrjGp9gOhKgFWz7jNqlxQQh/bvLt +BHj/YHcCT32TFf7AciZK/gDT+8D9a3rTzBKFhmCoHnCyJlqF/EPlA29VEL2rOFR8 +638MIXSWCnK2LXCD6V7x+l9KKyJndh5TFlcdUIZ7YOpDcnWrRNjzuCkzb2KK2cdD +URekeL5RAoGBAPMTEGHCwBkq2tB93tWl3M6rMqs2pLoWv+r74dIBhSdvzFhq7vrL +TGwR59JhXPlcde97ANyZpulxEIKzVJE0mRHFebnNxz+MmRVcj4cNeE4b1GKwmx00 +hcy2RSjM+9YnFFLUWyZIPKY0NiW3aBC98aPn0biiG6ZGIXJVmAlladz1AoGBANeN +J8YTLpVb7p5+B9nbSM3mvx+ZtAifAeDR792nTSN7DjQSYOfNrzTqdfqveSPtrpnZ +wgMa9nQyFFtMp0eDB835dy/ZA/w918H5YwFgabgTQ+eBJjZNI2iSyptITCbieUHV +MOin5nlhonx1jirhZEHDS8gGoIV3TQQlzu/E2g4zAoGAIr7e4JqOCwrtLFBRwghr +f79JBuBQu6j01gobRYGiHvkEJL9kWcUlr2z/zjrMp3hoA0t53A66pTPcQFKSDA+Q +sdGgjMa1bIgUedE5UvzB7ahcu56zDYGsfo6vZB2pAfukFBL21IoO4VMlSk7lOT9t +gxhoChRiD2qG7Wj+ypkMgOECgYB7LSvcchu9uHJM2gKMiVY6a7EuUrxh7NO68N1c +0f0v2GNOeG4uKQkFeTKAVgQo9us++gR3l9Hcpr2hStWQ9RzhpLxqeF5hp8mDDIt6 +PulLCp9UTSZUA5LHcJMdV5xE4EigyT6QxVncZWHgM6FRecm8FulYXgkfHATD6QMv +W1OspwKBgQDviiVBtlUvRWo9wUs1Y1tYCwBjFVztaJBGQ+Qx5uhYAhSobwUTW/MI +1lrxpGWaBfe63Iy+3V8v7YLU/bjjUMrzNFTrvoERwoRndL5EDqL5clljHO5kW+2g +wXfNa8BPj2EiqmmMcM3rcxd7Kw7qvEFLeJk9WE6EvKjvYiirr20mhQ== +-----END RSA PRIVATE KEY----- diff --git a/examples/resize_base/id_rsa.pub b/examples/resize_base/id_rsa.pub new file mode 100644 index 000000000..64cf06639 --- /dev/null +++ b/examples/resize_base/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMqwoGGtvOrlSvzS0MTa3l+wCQnmoeebnDS/1wRUqSQ+B5ROL5WzCgEAUyN/WdMpsZkASxdLyemEPhdRF3O1X6nWbteinNLW4LQMPI+blPFam0xJ1kBLYMDSXR57K8qY0a94opyuAUCPAwQ2vezKPB80pqjnBphKQsG++CnqhaQ8kbtEpIRHrP+fUkGEmgbAC7ymU2wtZGGGhisYxpVOw5xiPaiEU0zdzn1RqvAs+wqVXZNEk8WkuQabr0FgxHZ/EfIUufWIQy/LbVfTByzhuHZIsHypO7W4OSjoyd4ACUVCA+C8lwhhaGB3IiLRUaFq288UfgTQLbB8AOpXe6zmrP duncan@piscolita.suse.de diff --git a/examples/resize_base/main.tf b/examples/resize_base/main.tf new file mode 100644 index 000000000..b5dc91dec --- /dev/null +++ b/examples/resize_base/main.tf @@ -0,0 +1,73 @@ +provider "libvirt" { + uri = "qemu:///system" +} + +resource "libvirt_volume" "os_image_ubuntu" { + name = "os_image_ubuntu" + pool = "default" + source = "https://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img" + +} +resource "libvirt_volume" "ubuntu_resize_disk" { + name = "disk" + base_volume_id = "${libvirt_volume.os_image_ubuntu.id}" + pool = "default" + size = 5361393152 +} + +# Use CloudInit to add our ssh-key to the instance +resource "libvirt_cloudinit" "ubuntu_resize_disk_init" { + name = "ubuntu_resize_disk.iso" + pool = "default" + user_data = < Date: Mon, 10 Sep 2018 23:56:54 +0200 Subject: [PATCH 3/7] Refactor volume resource backing-store code to follow new size semantics --- libvirt/resource_libvirt_volume.go | 112 +++++++++++++---------------- 1 file changed, 51 insertions(+), 61 deletions(-) diff --git a/libvirt/resource_libvirt_volume.go b/libvirt/resource_libvirt_volume.go index a336e26c2..edb145842 100644 --- a/libvirt/resource_libvirt_volume.go +++ b/libvirt/resource_libvirt_volume.go @@ -102,8 +102,7 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error volumeDef.Name = d.Get("name").(string) var ( - img image - volume *libvirt.StorageVol + img image ) givenFormat, isFormatGiven := d.GetOk("format") @@ -151,82 +150,73 @@ func resourceLibvirtVolumeCreate(d *schema.ResourceData, meta interface{}) error volumeDef.Capacity.Unit = "B" volumeDef.Capacity.Value = size } else { - _, noSize := d.GetOk("size") - _, noBaseVol := d.GetOk("base_volume_id") - if noSize && noBaseVol { - return fmt.Errorf("'size' needs to be specified if no 'source' or 'base_volume_id' is given") - } - volumeDef.Capacity.Value = uint64(d.Get("size").(int)) - } + // the volume does not have a source image to upload, first handle + // whether it has a backing image + // + // backing images can be specified by either (id), or by (name, pool) + var baseVolume *libvirt.StorageVol - if baseVolumeID, ok := d.GetOk("base_volume_id"); ok { - if _, ok := d.GetOk("base_volume_name"); ok { - return fmt.Errorf("'base_volume_name' can't be specified when also 'base_volume_id' is given") - } - - volume = nil - baseVolume, err := client.libvirt.LookupStorageVolByKey(baseVolumeID.(string)) - if err != nil { - return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeID.(string), err) - } - backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume) - if err != nil { - return fmt.Errorf("Could not retrieve backing store %s", baseVolumeID.(string)) + if baseVolumeID, ok := d.GetOk("base_volume_id"); ok { + if _, ok := d.GetOk("base_volume_name"); ok { + return fmt.Errorf("'base_volume_name' can't be specified when also 'base_volume_id' is given") + } + baseVolume, err = client.libvirt.LookupStorageVolByKey(baseVolumeID.(string)) + if err != nil { + return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeID.(string), err) + } } - volumeDef.BackingStore = &backingStoreDef - } - - if baseVolumeName, ok := d.GetOk("base_volume_name"); ok { - volume = nil - baseVolumePool := pool - if _, ok := d.GetOk("base_volume_pool"); ok { - baseVolumePoolName := d.Get("base_volume_pool").(string) - baseVolumePool, err = client.libvirt.LookupStoragePoolByName(baseVolumePoolName) + if baseVolumeName, ok := d.GetOk("base_volume_name"); ok { + baseVolumePool := pool + if _, ok := d.GetOk("base_volume_pool"); ok { + baseVolumePoolName := d.Get("base_volume_pool").(string) + baseVolumePool, err = client.libvirt.LookupStoragePoolByName(baseVolumePoolName) + if err != nil { + return fmt.Errorf("can't find storage pool '%s'", baseVolumePoolName) + } + defer baseVolumePool.Free() + } + baseVolume, err = baseVolumePool.LookupStorageVolByName(baseVolumeName.(string)) if err != nil { - return fmt.Errorf("can't find storage pool '%s'", baseVolumePoolName) + return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeName.(string), err) } - defer baseVolumePool.Free() - } - baseVolume, err := baseVolumePool.LookupStorageVolByName(baseVolumeName.(string)) - if err != nil { - return fmt.Errorf("Can't retrieve volume %s: %v", baseVolumeName.(string), err) - } - backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume) - if err != nil { - return fmt.Errorf("Could not retrieve backing store %s", baseVolumeName.(string)) } - // does the backing store have some size information, check at least that it is not smaller than the backing store? - volumeDef.Capacity.Value = uint64(d.Get("size").(int)) - if _, ok := d.GetOk("size"); ok { - backingStoreVolumeDef, err := newDefVolumeFromLibvirt(baseVolume) + if baseVolume != nil { + backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume) if err != nil { - return err + return fmt.Errorf("Could not retrieve backing store definition: %s", err.Error()) } - if backingStoreVolumeDef.Capacity != nil && volumeDef.Capacity.Value < backingStoreVolumeDef.Capacity.Value { - return fmt.Errorf("When 'size' is specified, it shouldn't be smaller than the backing store specified with 'base_volume_id'") + // does the backing store have some size information?, check at least that it is not smaller than the backing store + volumeDef.Capacity.Value = uint64(d.Get("size").(int)) + if _, ok := d.GetOk("size"); ok { + backingStoreVolumeDef, err := newDefVolumeFromLibvirt(baseVolume) + if err != nil { + return err + } + + if backingStoreVolumeDef.Capacity != nil && volumeDef.Capacity.Value < backingStoreVolumeDef.Capacity.Value { + return fmt.Errorf("When 'size' is specified, it shouldn't be smaller than the backing store specified with 'base_volume_id' or 'base_volume_name/base_volume_pool'") + } } + volumeDef.BackingStore = &backingStoreDef } - volumeDef.BackingStore = &backingStoreDef } - if volume == nil { - volumeDefXML, err := xml.Marshal(volumeDef) - if err != nil { - return fmt.Errorf("Error serializing libvirt volume: %s", err) - } + volumeDef.Capacity.Value = uint64(d.Get("size").(int)) + volumeDefXML, err := xml.Marshal(volumeDef) + if err != nil { + return fmt.Errorf("Error serializing libvirt volume: %s", err) + } - // create the volume - v, err := pool.StorageVolCreateXML(string(volumeDefXML), 0) - if err != nil { - return fmt.Errorf("Error creating libvirt volume: %s", err) - } - volume = v - defer volume.Free() + // create the volume + volume, err := pool.StorageVolCreateXML(string(volumeDefXML), 0) + if err != nil { + return fmt.Errorf("Error creating libvirt volume: %s", err) } + defer volume.Free() // we use the key as the id key, err := volume.GetKey() From 6bc6c8183e44db15ea9b8398b35d3c9fe46fadff Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Tue, 11 Sep 2018 08:15:47 +0200 Subject: [PATCH 4/7] Add output variable ip to example --- examples/resize_base/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/resize_base/main.tf b/examples/resize_base/main.tf index b5dc91dec..9626c87c5 100644 --- a/examples/resize_base/main.tf +++ b/examples/resize_base/main.tf @@ -71,3 +71,6 @@ resource "libvirt_domain" "domain_ubuntu_resized" { } } +output "ip" { + value = "${libvirt_domain.domain_ubuntu_resized.network_interface.0.addresses.0}" +} From 347a3f2b745a5cdaf5d279ee9e299a7ff0c08739 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Sat, 22 Sep 2018 00:17:43 +0200 Subject: [PATCH 5/7] Port example to libvirt_cloudinit_disk --- examples/resize_base/main.tf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/resize_base/main.tf b/examples/resize_base/main.tf index 9626c87c5..b3909e794 100644 --- a/examples/resize_base/main.tf +++ b/examples/resize_base/main.tf @@ -6,9 +6,9 @@ resource "libvirt_volume" "os_image_ubuntu" { name = "os_image_ubuntu" pool = "default" source = "https://cloud-images.ubuntu.com/releases/xenial/release/ubuntu-16.04-server-cloudimg-amd64-disk1.img" - } -resource "libvirt_volume" "ubuntu_resize_disk" { + +resource "libvirt_volume" "disk_ubuntu_resized" { name = "disk" base_volume_id = "${libvirt_volume.os_image_ubuntu.id}" pool = "default" @@ -16,8 +16,8 @@ resource "libvirt_volume" "ubuntu_resize_disk" { } # Use CloudInit to add our ssh-key to the instance -resource "libvirt_cloudinit" "ubuntu_resize_disk_init" { - name = "ubuntu_resize_disk.iso" +resource "libvirt_cloudinit_disk" "cloudinit_ubuntu_resized" { + name = "cloudinit_ubuntu_resized.iso" pool = "default" user_data = < Date: Sat, 22 Sep 2018 00:18:06 +0200 Subject: [PATCH 6/7] Document how to run example --- examples/resize_base/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/examples/resize_base/README.md b/examples/resize_base/README.md index 56b76ed32..ec8aa8dcc 100644 --- a/examples/resize_base/README.md +++ b/examples/resize_base/README.md @@ -2,3 +2,10 @@ This example takes a base image of 2G and uses it as the backing store of a bigger volume. _cloud-init_ is then used to resize the original partition to the new available space. See https://github.com/dmacvicar/terraform-provider-libvirt/issues/369 + +# Running + +```console +$ terraform apply +$ ssh -i id_rsa "root@$(terraform output ip)" +``` From 3580e3e3af542996a98e74a8e52dc67a7d627031 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Sat, 22 Sep 2018 00:29:13 +0200 Subject: [PATCH 7/7] Document that size can be specified with base volumes --- website/docs/r/volume.html.markdown | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/docs/r/volume.html.markdown b/website/docs/r/volume.html.markdown index 78ef62f87..89745f0f1 100644 --- a/website/docs/r/volume.html.markdown +++ b/website/docs/r/volume.html.markdown @@ -55,6 +55,9 @@ The following arguments are supported: * `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. * `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