Skip to content

Commit

Permalink
Merge pull request #416 from dmacvicar/size_with_backing_volume
Browse files Browse the repository at this point in the history
Able to specifiy size when using backing volume (and able to resize partitions with cloud-init)
  • Loading branch information
dmacvicar authored Sep 23, 2018
2 parents c37707c + 3580e3e commit df6aed4
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 59 deletions.
4 changes: 4 additions & 0 deletions examples/resize_base/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.img
*.qcow2
*.tfstate*
.terraform
11 changes: 11 additions & 0 deletions examples/resize_base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

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)"
```
27 changes: 27 additions & 0 deletions examples/resize_base/id_rsa
Original file line number Diff line number Diff line change
@@ -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-----
1 change: 1 addition & 0 deletions examples/resize_base/id_rsa.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDMqwoGGtvOrlSvzS0MTa3l+wCQnmoeebnDS/1wRUqSQ+B5ROL5WzCgEAUyN/WdMpsZkASxdLyemEPhdRF3O1X6nWbteinNLW4LQMPI+blPFam0xJ1kBLYMDSXR57K8qY0a94opyuAUCPAwQ2vezKPB80pqjnBphKQsG++CnqhaQ8kbtEpIRHrP+fUkGEmgbAC7ymU2wtZGGGhisYxpVOw5xiPaiEU0zdzn1RqvAs+wqVXZNEk8WkuQabr0FgxHZ/EfIUufWIQy/LbVfTByzhuHZIsHypO7W4OSjoyd4ACUVCA+C8lwhhaGB3IiLRUaFq288UfgTQLbB8AOpXe6zmrP [email protected]
76 changes: 76 additions & 0 deletions examples/resize_base/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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" "disk_ubuntu_resized" {
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_disk" "cloudinit_ubuntu_resized" {
name = "cloudinit_ubuntu_resized.iso"
pool = "default"
user_data = <<EOF
#cloud-config
disable_root: 0
ssh_pwauth: 1
users:
- name: root
ssh-authorized-keys:
- ${file("id_rsa.pub")}
growpart:
mode: auto
devices: ['/']
EOF
}

resource "libvirt_domain" "domain_ubuntu_resized" {
name = "doman_ubuntu_resized"
memory = "512"
vcpu = 1

cloudinit = "${libvirt_cloudinit_disk.cloudinit_ubuntu_resized.id}"

network_interface {
network_name = "default"
wait_for_lease = true
}

# IMPORTANT
# Ubuntu can hang if an isa-serial is not present at boot time.
# If you find your CPU 100% and never is available this is why
console {
type = "pty"
target_port = "0"
target_type = "serial"
}

console {
type = "pty"
target_type = "virtio"
target_port = "1"
}

disk {
volume_id = "${libvirt_volume.disk_ubuntu_resized.id}"
}

graphics {
type = "spice"
listen_type = "address"
autoport = true
}
}

output "ip" {
value = "${libvirt_domain.domain_ubuntu_resized.network_interface.0.addresses.0}"
}
114 changes: 55 additions & 59 deletions libvirt/resource_libvirt_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -151,76 +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))
}

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")
}
// 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 _, 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 {
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")
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 retrieve volume %s: %v", baseVolumeName.(string), err)
}
}

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 baseVolume != nil {
backingStoreDef, err := newDefBackingStoreFromLibvirt(baseVolume)
if err != nil {
return fmt.Errorf("can't find storage pool '%s'", baseVolumePoolName)
return fmt.Errorf("Could not retrieve backing store definition: %s", err.Error())
}
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 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()
Expand Down
3 changes: 3 additions & 0 deletions website/docs/r/volume.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit df6aed4

Please sign in to comment.